﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nop.Services.Media
{
    public class ImageUtil
    {
        /// <summary>
        /// add water text mark
        /// </summary>
        /// <param name="img">original picture﻿(﻿System.Drawing)</param>
        /// <param name="watermarkText">water text</param>
        /// <param name="watermarkStatus">water text mark position</param>
        /// <param name="quality">water mark quality(1~100)</param>
        /// <param name="fontname">water text mark fontname</param>
        /// <param name="fontsize">water text mark fontsize</param>
        public static byte[] ImageWaterMarkText(Image img, string watermarkText, Locative watermarkStatus, long quality = 100, string fontname = "Consolas", int fontsize = 18)
        {
            Graphics g = null;
            Byte[] resultBytes = null;
            try
            {
                g = Graphics.FromImage(img);
                var drawFont = new Font(fontname, fontsize, FontStyle.Regular, GraphicsUnit.Pixel);
                SizeF crSize = g.MeasureString(watermarkText, drawFont);

                float xpos = 0;
                float ypos = 0;
                SetWaterMarkTextLocative(watermarkStatus, img.Width, img.Height, crSize, ref xpos, ref ypos);

                g.DrawString(watermarkText, drawFont, new SolidBrush(Color.Black), xpos, ypos);

                ImageCodecInfo ici = null;
                foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders().Where(codec => codec.MimeType.IndexOf("jpeg") > -1))
                {
                    ici = codec;
                }

                var encoderParams = new EncoderParameters();
                encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, new long[] { (quality < 0 || quality > 100) ? 80 : quality });

                using (Stream resultStream = new MemoryStream())
                {
                    if (ici != null)
                    {
                        img.Save(resultStream, ici, encoderParams);
                        resultBytes = new byte[resultStream.Length];
                        resultStream.Position = 0;//设置留的初始位置
                        resultStream.Read(resultBytes, 0, Convert.ToInt32(resultStream.Length));
                    }
                    return resultBytes;
                }
            }
            finally
            {
                if (g != null) g.Dispose();
                img.Dispose();
            }
        }

        /// <summary>
        /// create thumbnail image
        /// </summary>
        /// <param name="extension">extension</param>
        /// <param name="b">image bitmap</param>
        /// <param name="newSize">new size</param>
        /// <param name="quality">image's quality</param>
        /// <returns>byte[]</returns>
        public static byte[] DoCreateImage(string extension, Bitmap b, Size newSize, long quality)
        {
            byte[] bytes = null;

            using (var newBitMap = new Bitmap(newSize.Width, newSize.Height))
            {
                using (var g = Graphics.FromImage(newBitMap))
                {
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.DrawImage(b, 0, 0, newSize.Width, newSize.Height);
                    var ep = new EncoderParameters();
                    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
                    ImageCodecInfo ici =GetImageCodecInfoFromExtension(extension);
                    if (ici == null)
                        ici = ImageUtil.GetImageCodecInfoFromMimeType("image/jpeg");

                    using (MemoryStream memStream = new MemoryStream())
                    {
                        newBitMap.Save(memStream, ici, ep);
                        memStream.Seek(0, SeekOrigin.Begin);
                        bytes = memStream.ToArray();
                    }
                }
            }
            return bytes;
        }

        //set watertext size
        private static void SetWaterMarkTextLocative(Locative watermarkStatus, int width, int height, SizeF crSize, ref float xpos, ref float ypos)
        {
            switch (watermarkStatus)
            {
                case Locative.LeftUp:
                    xpos = xpos * (float).01;
                    ypos = height * (float).01;
                    break;
                case Locative.CenterUp:
                    xpos = (width * (float).50) - (crSize.Width / 2);
                    ypos = height * (float).01;
                    break;
                case Locative.RightUp:
                    xpos = (width * (float).99) - crSize.Width;
                    ypos = height * (float).01;
                    break;
                case Locative.LeftCenter:
                    xpos = width * (float).01;
                    ypos = (height * (float).50) - (crSize.Height / 2);
                    break;
                case Locative.Center:
                    xpos = (width * (float).50) - (crSize.Width / 2);
                    ypos = (height * (float).50) - (crSize.Height / 2);
                    break;
                case Locative.RightCenter:
                    xpos = (width * (float).99) - crSize.Width;
                    ypos = (height * (float).50) - (crSize.Height / 2);
                    break;
                case Locative.LeftDown:
                    xpos = width * (float).01;
                    ypos = (height * (float).99) - crSize.Height;
                    break;
                case Locative.CenterDown:
                    xpos = (width * (float).50) - (crSize.Width / 2);
                    ypos = (height * (float).99) - crSize.Height;
                    break;
                case Locative.RightDown:
                    xpos = (width * (float).99) - crSize.Width;
                    ypos = (height * (float).99) - crSize.Height;
                    break;
            }
        }

        /// <summary>
        /// Calculates picture dimensions whilst maintaining aspect
        /// </summary>
        /// <param name="originalSize">The original picture size</param>
        /// <param name="targetSize">The target picture size (longest side)</param>
        /// <returns></returns>
        public static Size CalculateDimensions(Size originalSize, int targetSize)
        {
            var newSize = new Size();
            if (originalSize.Height > originalSize.Width) // portrait 
            {
                newSize.Width = (int)(originalSize.Width * (float)(targetSize / (float)originalSize.Height));
                newSize.Height = targetSize;
            }
            else // landscape or square
            {
                newSize.Height = (int)(originalSize.Height * (float)(targetSize / (float)originalSize.Width));
                newSize.Width = targetSize;
            }
            return newSize;
        }

        /// <summary>
        /// Returns the first ImageCodecInfo instance with the specified extension.
        /// </summary>
        /// <param name="fileExt">File extension</param>
        /// <returns>ImageCodecInfo</returns>
        public static ImageCodecInfo GetImageCodecInfoFromExtension(string fileExt)
        {
            fileExt = fileExt.TrimStart(".".ToCharArray()).ToLower().Trim();
            switch (fileExt)
            {
                case "jpg":
                case "jpeg":
                    return GetImageCodecInfoFromMimeType("image/jpeg");
                case "png":
                    return GetImageCodecInfoFromMimeType("image/png");
                case "gif":
                    //use png codec for gif to preserve transparency
                    //return GetImageCodecInfoFromMimeType("image/gif");
                    return GetImageCodecInfoFromMimeType("image/png");
                default:
                    return GetImageCodecInfoFromMimeType("image/jpeg");
            }
        }

        /// <summary>
        /// Returns the first ImageCodecInfo instance with the specified mime type.
        /// </summary>
        /// <param name="mimeType">Mime type</param>
        /// <returns>ImageCodecInfo</returns>
        public static ImageCodecInfo GetImageCodecInfoFromMimeType(string mimeType)
        {
            var info = ImageCodecInfo.GetImageEncoders();
            return info.FirstOrDefault(ici => ici.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase));
        }
    }
}
